#!/bin/bash
#
##############################################################################
#                                                                            #
#                         Pi-Star Find Modem Tool.                           #
#                                                                            #
#     Version 1.3, Code, Design and Development by Andy Taylor (MW0MWZ).     #
#                                                                            #
#              Make it simple to find the attached MMDVM Modem               #
#                                                                            #
##############################################################################
#
# Make sure we are root, if we cant stop the services, the results are a bit hit and miss.
if [ "$(id -u)" != "0" ]; then
  echo -e "You need to be root to run this command...\n"
  exit 1
fi

function resetGPIOModem {
        # Reset GPIO connected Modems
        echo 20 > /sys/class/gpio/export
        echo 21 > /sys/class/gpio/export
        echo out > /sys/class/gpio/gpio20/direction
        echo out > /sys/class/gpio/gpio21/direction
        sleep 0.5
        echo 0 > /sys/class/gpio/gpio20/value
        echo 0 > /sys/class/gpio/gpio21/value
        echo 1 > /sys/class/gpio/gpio21/value
        sleep 1
        echo 0 > /sys/class/gpio/gpio20/value
        echo 1 > /sys/class/gpio/gpio20/value
        echo 0 > /sys/class/gpio/gpio20/value
        sleep 0.5
        echo 20 > /sys/class/gpio/unexport
        echo 21 > /sys/class/gpio/unexport
        # Let the modem boot, or this script cant find it
        sleep 2
}

# Kill any MMDVMHost or DStarRepeater processes
if [[ $(/usr/bin/pgrep MMDVMHost) ]]; then
        systemctl stop mmdvmhost > /dev/null 2>&1
        svcRestart=mmdvmhost
fi
if [[ $(/usr/bin/pgrep dstarrepeaterd) ]]; then
        systemctl stop dstarrepeaterd > /dev/null 2>&1
        svcRestart=dstarrepeaterd
fi
resetGPIOModem

# Random Filename
randomFilename=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)

function readDevice {
        # Setup the variables
        serialProtocol=$1
        serialSpeed=$2

        # Talk to the hardware
        stty -F ${modemDevice} ${serialSpeed} raw -echo                         # Configure the serial port, its always 115200
        exec 3<${modemDevice}                                                   # Redirect the output from serial to file descriptor 3
        cat <&3 > /tmp/${randomFilename} &                                      # Get the content of FD3 and punt it to a file
        PID=$!                                                                  # Save the PID for the cat command, to dump it later

        # Case switch makes much more sense here since we now have a few protocols
        case ${serialProtocol} in
                mmdvm)
                        echo -en '\xE0\x03\x00' > ${modemDevice}                # Send the "Get Version" command to the port
                ;;
                dvmega)
                        echo -en '\xD0\x01\x00\x11\x00\x0B' > ${modemDevice}    # Send the "Get Version" command to the port
                ;;
                nextion)
                        echo -en '\xFF\xFF\xFF' > ${modemDevice}                # Send the "Clear" command to the port
                        echo -en 'connect' > ${modemDevice}                     # Send the "Connect" command to the port
                        echo -en '\xFF\xFF\xFF' > ${modemDevice}                # Send the "Clear" command to the port
                ;;
        esac

        sleep 0.2s                                                              # Wait for a responce
        kill -9 $PID > /dev/null 2>&1                                           # Kill the cat!
        exec 3<&- 1> /dev/stdout 2> /dev/null                                   # Free up FD3
}

function checkMMDVMoutput {
        serialSpeed=$1
        if [[ $(cat /tmp/${randomFilename} | wc -c) -ge 16 ]]; then
                # OK we have some output, clean up the modem version string and remove non-printables
                modemData=$(tr -cd '[[:print:]]' < /tmp/${randomFilename} | sed 's/^.*MMDVM/MMDVM/g' | sed 's/^.*DVMEGA/DVMEGA/g' | sed 's/^.*D2RG_MMDVM/D2RG_MMDVM/g' | sed 's/^.*ZUMspot/ZUMspot/g' | sed 's/^.*Nano_/Nano_/g' | sed 's/^.*OpenGD77_HS/OpenGD77_HS/g' | sed 's/^.*SkyBridge/SkyBridge/g')
                protocolVersion=$(xxd -p -l1 -s 3 /tmp/${randomFilename})

                # OK we have some output, format it into somthing useful.
                case ${modemData} in
                        MMDVM_HS*)
                                mmdvmClass="MMDVM_HS"
                        ;;
                        MMDVM*)
                                mmdvmClass="MMDVM   "
                        ;;
                        D2RG_MMDVM_HS*)
                                mmdvmClass="MMDVM_HS"
                        ;;
                        HS_Hat*)
                                mmdvmClass="MMDVM_HS"
                        ;;
                        ZUMspot*)
                                mmdvmClass="MMDVM_HS"
                        ;;
                        Nano_*)
                                mmdvmClass="MMDVM_HS"
                        ;;
                        OpenGD77_HS*)
                                mmdvmClass="MMDVM_HS"
                        ;;
                        SkyBridge*)
                                mmdvmClass="MMDVM_HS"
                        ;;
                        DVMEGA*)
                                mmdvmClass="DV-Mega "
                        ;;
                        DV-MEGA*)
                                mmdvmClass="DV-Mega "
                        ;;
                        *u-blox*)
                                mmdvmClass="GPS     "
                        ;;
                        *)
                                mmdvmClass="Unknown "
                        ;;
                esac

                case ${modemDevice} in
                        /dev/ttyS*)
                                mmdvmPort="GPIO"
                        ;;
                        /dev/ttyAMA*)
                                mmdvmPort="GPIO"
                        ;;
                        /dev/ttyACM*)
                                mmdvmPort="USB"
                        ;;
                        /dev/ttyUSB*)
                                mmdvmPort="USB"
                        ;;
                esac

                case ${protocolVersion} in
                        01)
                              mmdvmProtocolVer="V1"
                        ;;
                        02)
                              mmdvmProtocolVer="V2"
                        ;;
                        *)
                              mmdvmProtocolVer="Unknown"
                        ;;
                esac

                if [[ ${modemData} == "MMDVM"* || ${modemData} == "HS_Hat"* || ${modemData} == "D2RG_MMDVM_HS"* || ${modemData} == "ZUMspot"* || ${modemData} == "Nano_"* ]]; then
                        # Print the output
                        echo -e "Detected ${mmdvmClass} Port: ${modemDevice} (${mmdvmPort}) Baud: ${serialSpeed} Protocol: ${mmdvmProtocolVer} \n\t Modem Data: ${modemData}"
                        boardDetected="true"
                elif [[ ${modemData} == "DV-MEGA"* || ${modemData} == "DVMEGA"* ]]; then
                        # Print the output
                        echo -e "Detected ${mmdvmClass} Port: ${modemDevice} (${mmdvmPort}) Baud: ${serialSpeed} Protocol: ${mmdvmProtocolVer} \n\t Modem Data: ${modemData} - MMDMVM Protocol"
                        boardDetected="true"
                elif [[ ${modemData} == *"u-blox"* ]]; then
                        # Print the output
                        echo -e "Detected ${mmdvmClass} Port: ${modemDevice} (${mmdvmPort}) Baud: ${serialSpeed} \n\t Modem Data: u-blox GPS Device"
                        boardDetected="true"
                fi
                echo "" > /tmp/${randomFilename}
        fi
}

function checkDVMEGAoutput {
        serialSpeed=$1
        if [[ $(cat /tmp/${randomFilename} | wc -c) -ge 16 ]]; then
                # OK we have some output, clean up the string and remove non-printables
                dvmegaData=$(tr -cd '\11\12\15\40-\176' < /tmp/${randomFilename})

                # Sanity check the output from the DV-Mega
                if [[ ${dvmegaData} == *"DV-MEGA"* ]]; then
                        # Clean up the port information
                        if [[ ${modemDevice} == *"USB"* ]]; then
                                dvmegaPort="USB"
                        else
                                dvmegaPort="GPIO"
                        fi
                fi

                if [[ ${dvmegaData} == "DV-MEGA"* || ${dvmegaData} == "DVMEGA"* ]]; then
                        # Print the output
                        echo -e "Detected DV-Mega  Port: ${modemDevice} (${dvmegaPort}) Baud: ${serialSpeed} \n\t Modem Data: ${dvmegaData}  - DStarRepeater Protocol"
                        boardDetected="true"
                fi
                if [[ ${dvmegaData} == *"u-blox"* ]]; then
                        # Print the output
                        echo -e "Detected GPS      Port: ${modemDevice} (${dvmegaPort}) Baud: ${serialSpeed} \n\t Modem Data: u-blox GPS Device"
                        boardDetected="true"
                fi
                echo "" > /tmp/${randomFilename}
        fi
}

function checkNEXTIONoutput {
        serialSpeed=$1
        # Read the output, and make it pretty for humans...
        if [[ $(cat /tmp/${randomFilename} | wc -c) -ge 16 ]]; then
                # OK we have some output, clean up the string and remove non-printables
                nextionData=$(tr -cd '\11\12\15\40-\176' < /tmp/${randomFilename})

                # OK we have some output (example below), format it into somthing useful.
                # comok 1,37697-0,NX3224T024_011R,99,61488,DE6788B2935E5731,4194304???
                if [[ $(grep "comok" /tmp/${randomFilename}) && ${nextionData} == *"NX"* ]]; then
                        nextionModel=$(echo ${nextionData} | awk -F',' '{print $3}')
                        nextionTouch=$(echo ${nextionData} | awk -F',' '{print $1}')
                        nextionSerial=$(echo ${nextionData} | awk -F',' '{print $6}')

                        # Clean up the port information
                        if [[ ${modemDevice} == *"USB"* ]]; then
                                nextionPort="USB"
                        else
                                nextionPort="GPIO"
                        fi

                        # Show Touchscreen support
                        if [[ ${nextionTouch} ]]; then
                                nextionTouch="Yes"
                        else
                                nextionTouch="No"
                        fi

                        # Print the output
                        echo -e "Detected Nextion  Port: ${modemDevice} (${nextionPort}) Baud: ${serialSpeed} \n\t Model: ${nextionModel} Serial: ${nextionSerial} Touch: ${nextionTouch}"
                        boardDetected="true"
                fi
                echo "" > /tmp/${randomFilename}
        fi
}

# Find all the possible devices (only looking at /dev/ttyAMA* /dev/ttyACM* /dev/ttyS* and /dev/ttyUSB*)
for modemDevice in $(find /dev/tty* ! -type l | grep -E "tty(AMA|ACM|USB|S)."); do
        # Ignore the /dev/ttyS[0-3] ports on the Odroid Platform.
        if [[ $(platformDetect.sh) == *"Odroid"* && ${modemDevice} == *"ttyS"* && ${modemDevice} != *"ttySAC"* ]]; then
                continue
        fi

        # Ignore /dev/ttyS0 on the NanoPi Platform
        if [[ $(platformDetect.sh) == *"sun8i"* && ${modemDevice} == *"ttyS0"* ]]; then
                continue
        fi

        # Ignore /dev/ttyS0 and /dev/ttySC* devices
        if [[ ${modemDevice} == *"ttySC"* || ${modemDevice} == *"ttyS0" ]]; then
                continue
        fi

        # Make sure the output file exists
        touch /tmp/${randomFilename}                                            # Make the output File

        # Send the MMDVM "Get Version" command to test the ports.
        boardDetected="false"
        for speed in 115200 230400 460800
        do
                # Try MMDVM Protocol
                if [ "${boardDetected}" == "true" ]; then
                        break
                fi
                readDevice mmdvm ${speed}
                checkMMDVMoutput ${speed}
        done

        # Sent the DVMega "Get Version" Command
        boardDetected="false"
        readDevice dvmega 115200                                                # Try DVMega Protocol
        checkDVMEGAoutput 115200

        # Detect Nextion Screens
        boardDetected="false"
        for speed in 2400 4800 9600 19200 31250 38400 57600 115200 230400 250000 256000 512000 921600
        do
                # Try Nextion Protocol
                if [ "${boardDetected}" == "true" ]; then
                        break
                fi
                readDevice nextion ${speed}
                checkNEXTIONoutput ${speed}
        done

        # Dump the temp file we used
        rm -rf /tmp/${randomFilename}
done

# Restart the service(s) if I stopped them
resetGPIOModem
if [[ -v svcRestart ]]; then
        systemctl start ${svcRestart} > /dev/null 2>&1
fi
